//#include <QtCore/QCoreApplication>

#include <Sniffer/sniffer.h>
#include "commandLineParser.h"
#include "helper.h"
#include "dnsdb.h"
#include "rerequestor.h"
#include <QString>
#include <QStringList>
#include <QVector>
#include <Packet/Inet/ipv4.h>
#include <QFile>
#include <QTextStream>

//#include "topQueriesProcessor.h"
//#include "processor.h"

const QString DEFAULT_HOST = "127.0.0.1";
const QString DEFAULT_DBUSER = "dnsbot";
const QString DEFAULT_DB = "dnsdb";
const QString DEFAULT_DBTYPE = "MYSQL";
const std::string DEFAULT_FILTER = "udp port 53 || tcp port 53";

void printHelp();
Rerequestor makeRerequestor( const QString &string );
QVector< Rerequestor > readRerequestConfig( const QString &rerequestConfig );

int main(int argc, char *argv[])
{
  //QCoreApplication a(argc, argv);
  //return a.exec();

  QString dbpass = parser( argc, argv, "-P" ).c_str();
  if( dbpass == "set" )
  {
    std::string pass;
    std::cout << "password:";
    std::cin >> pass;
    dbpass = pass.c_str();
  }

  std::cout << "dnsdb v0.1 (C) 2011 Jeff Scaparra SPAWAR Systems Center Atlantic" << std::endl;

  //-- Handle Command Line --
  std::string help = parser( argc, argv, "-h" );
  if( help.size() > 0 )
  {
    printHelp();
    exit( 0 );
  }

  QString interfaces = parser(argc, argv, "-i").c_str();
  std::string pcap = parser( argc, argv, "-p" );
  std::string filter = parser( argc, argv, "-f" );
  std::string deviceInfo = parser( argc, argv, "--deviceInfo" );
  std::string redirectOnly = parser( argc, argv, "-R" );
  QString rerequestConfig = parser( argc, argv, "-r").c_str();
  QVector< Rerequestor > rerequestors;
  if( rerequestConfig.size() > 0 && rerequestConfig != "set" )
  {
    rerequestors = readRerequestConfig( rerequestConfig );
  }

  //-- initialization and error handeling base on CLI input

  if( filter.size() == 0 )
  {
    filter = DEFAULT_FILTER;
  }

  Sniffer mySniffer;

  if( deviceInfo.size() )
  {
    mySniffer.printDevices();
    exit(0);
  }

  if( (interfaces.size() == 0 && pcap.size() == 0) || (interfaces.size() > 0 && pcap.size() > 0) )
  {
    std::cerr << "USAGE: Please specify a device **OR** a pcap file for input" << std::endl;
    printHelp();
    exit( 0 );
  }

  if( filter.size() )
    mySniffer.setFilter( filter );

  if( pcap.size() )
    mySniffer.setInputPcapFile( pcap );

  if( interfaces.size() )
  {
    QStringList interfaceList = interfaces.split(',');
    for( int i = 0; i < interfaceList.size(); ++i )
    {
      mySniffer.addInputDevice( interfaceList[i].toStdString() );
    }
  }

  DNSDB db;
  if( redirectOnly.size() == 0 )
  {
    QString dbuser = parser( argc,argv, "-U" ).c_str();
    if( dbuser.size() == 0 )
      dbuser = DEFAULT_DBUSER;
    QString dbtype = parser( argc,argv, "-T" ).c_str();
    if( dbtype.size() == 0 )
      dbtype = DEFAULT_DBTYPE;
    QString dbname = parser( argc, argv, "-D" ).c_str();
    if( dbname.size() == 0 )
      dbname = DEFAULT_DB;
    QString dbhost = parser( argc, argv, "-H" ).c_str();
    if( dbhost.size() == 0 )
      dbhost = DEFAULT_HOST;

    db.setDB( dbname );
    db.setDBHost( dbhost );
    db.setDBUser( dbuser );
    db.setDBPassword( dbpass );
    db.setDBType( dbtype );
    db.dbConnect();
  }
  mySniffer.start();

  //Process Packets

  while( mySniffer.sniffing() )
  {
    Packet p  = mySniffer.popPacket();
    if( redirectOnly.size() == 0)
      db.insertPacket( p );
    for( int i = 0; i < rerequestors.size(); ++i )
      rerequestors[i].processPacket(p);
  }

  mySniffer.stop();
  return 0;
}

void printHelp()
{
  std::cout << "dnsdb (C) 2011 Jeff Scaparra SPAWAR Atlantic\n";
  std::cout << "\n";
  std::cout << "-h              \t print help\n";
  std::cout << "-H <host>       \t Database host (DEFAULT: " << DEFAULT_HOST.toStdString() << ")\n";
  std::cout << "-D <database>   \t Database name (DEFAULT: " << DEFAULT_DB.toStdString() << ")\n";
  std::cout << "-U <user>       \t Database user (DEFAULT: " << DEFAULT_DBUSER.toStdString() << ")\n";
  std::cout << "-P              \t Database password\n";
  std::cout << "-T <DBtype>     \t MYSQL, PSQL, or SQLITE (DEFAULT: " << DEFAULT_DBTYPE.toStdString() << ")\n";
  std::cout << "-f <filter>     \t tcpdump like filter (DEFAULT: " << DEFAULT_FILTER << ")\n";
  std::cout << "-i <interface(s)>  \t interface to listen on seperate with commas\n";
  std::cout << "-p <pcapfile>   \t pcap file to use for inpit\n";
  std::cout << "-R              \t Redirect only\n";
  std::cout << "-r redirect.conf\t rules for resending the requests to other DNS servers\n";
  std::cout << "--deviceInfo    \t print pcap devices " << std::endl;
}

Rerequestor makeRerequestor( const QString &string )
{
    QStringList origins = string.split(';');
    QString sip, sport, dip, dport, interface;
    if( origins.size() == 2 )
    {
        interface = origins.at(1);
        origins = origins.at(0).split("=");
        if( origins.size() == 2 )
        {
          QStringList source = origins[0].split('#');
          if( source.size() == 2 )
          {
            sip = source[0];
            sport = source[1];
          }
          QStringList destination = origins[1].split('#');
          if( destination.size() == 2 )
          {
            dip = destination[0];
            dport = destination[1];
          }
          Rerequestor requestor;
          if( sip.size() > 0 )
            requestor.setNewSource( stringToIPAddress( sip.toStdString()));
          if( sport.size() > 0 )
            requestor.setNewSourcePort( ss_atoi<uint16_t>( sport.toStdString() ));
          if( dip.size() > 0 )
            requestor.setNewDestination( stringToIPAddress( dip.toStdString()));
          if( dport.size() > 0 )
            requestor.setNewDestinationPort( ss_atoi<uint16_t>(dport.toStdString()));
          requestor.setDevice(interface.toStdString());
          return requestor;
        }
      }

    std::cerr << "Wrong rerequestor format!\n";
    std::cerr << "FORMAT: SIP#SPORT=DIP#DPORT" << std::endl;
    exit(1);
    return Rerequestor();
}

QVector< Rerequestor > readRerequestConfig( const QString &rerequestConfig )
{
  QVector< Rerequestor > requests;
  QFile file( rerequestConfig );
  QString line;
  if( !file.open(QIODevice::ReadOnly) )
  {
    std::cerr << "Could not open config file: " << rerequestConfig.toStdString() << std::endl;
    exit( 2 );
  }

  QTextStream stream( &file );

  while( !stream.atEnd() )
  {
    Rerequestor requestor;
    line = stream.readLine();
    QStringList parts = line.split(')');
    if( parts.size()  == 2 )
    {
      requestor = makeRerequestor(parts.at(1).trimmed() );
      QString name = parts.at(0);
      name = name.remove(0,1);
      requestor.setName( name.toStdString() );
      requests.push_back( requestor );
    }
    else if ( parts.size() == 1 )
    {
      requestor = makeRerequestor( parts.at(0).trimmed() );
      requests.push_back( requestor );
    }
    else
    {
      std::cerr << "Could not open config file: " << rerequestConfig.toStdString() << std::endl;
      exit( 2 );
    }
  }
  return requests;
}
